package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

import console.IOBuffer;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Michael Hanns
 *
 */
public class NetworkClientImp extends Thread implements NetworkClient {

    private Socket serverConnection;
    private IOBuffer terminal;
    private boolean recievingData;
    private long dataLastRecieved;
    private BufferedReader in;
    private PrintWriter out;
    String firstLine;

    public NetworkClientImp(IOBuffer term) {
        terminal = term;
        recievingData = false;
        dataLastRecieved = 0;
    }

    @Override
    public boolean connectToServer(final String ipaddr, final int port) {
        InetAddress ip;
        try {
            ip = InetAddress.getByName(ipaddr);
            serverConnection = new Socket(ip, port);
            in = new BufferedReader(new InputStreamReader(serverConnection.getInputStream()));
            out = new PrintWriter(serverConnection.getOutputStream(), true);
            firstLine = in.readLine();
        } catch (UnknownHostException ex) {
            Logger.getLogger(NetworkClientImp.class.getName()).log(Level.SEVERE, null, ex);
            terminal.writeTo("\nCould not connect to " + ipaddr + ":" + port + ". "
                    + "Unknown host.");
            return false;
        } catch (IOException ex) {
            Logger.getLogger(NetworkClientImp.class.getName()).log(Level.SEVERE, null, ex);
            terminal.writeTo("\nCould not connect to " + ipaddr + ":" + port + ". "
                    + "Address not found.");
            return false;
        }

        // Just a brief protocol to ensure the server is a WITNA server as client
        // has issues reading other MUD's.
        if (firstLine != null) { //  && firstLine.toUpperCase().startsWith("WITNA")
            recievingData = true;
            dataLastRecieved = System.currentTimeMillis();
            terminal.writeTo("\nConnection successful!\n\n" + firstLine);
            return true;
        } else {
            recievingData = false;
            terminal.writeTo("\nConnection failed: not a WITNA server!\n");
            return false;
        }
    }

    @Override
    public void run() {
        recieveData();
    }

    @Override
    public boolean connected() {
        boolean connected = recievingData;
        if (connected && dataLastRecieved + 1800000 < System.currentTimeMillis()) {
            out.println("DISCONNECT");
            recievingData = false;
            terminal.writeTo("\nDisconnected due to idle timeout.");
        }

        return recievingData;
    }

    private void recieveData() {
        try {
            String inputLine = "";
            while (recievingData) {
                inputLine = in.readLine();

                if (inputLine != null) {
                    terminal.writeTo(inputLine + "\n");

                    if (inputLine.toUpperCase().startsWith("YOU ARE NOW DISCONNECTED")) {
                        terminal.writeTo("\nConnection closed by foreign host.");
                        recievingData = false;
                    }
                }
            }
        } catch (IOException e) {
            terminal.writeTo("\nConnection closed by foreign host. Press type anything and press ENTER to return to the WITNA Shell.");
            recievingData = false;
        }
    }
    
// This version of the method does it on a character-by-character basis, rather
// than lines. The upshot of this is that it prints immediately as it recieves,
// which means it doesn't require the server to end everything with a new line.
// This makes it work with existing MUD's and opens up a realm of possibilities
// for WITNA's output. The downside is that it's taking WAAAAY too many processor
// cycles at the moment. Could be something to look into.
//
//    private void recieveData() {
//        try {
//            char input;
//            boolean buffering = false;
//            String bufferString = "";
//            while (recievingData) {
//                input = (char) in.read();
//
//                if (input == 27) {
//                    buffering = true;
//                }
//
//                if (buffering) {
//                    bufferString += input;
//                    if(input == 'm') {
//                        terminal.writeTo(bufferString);
//                        bufferString = "";
//                    }
//                } else {
//                    terminal.writeTo(input + "");
//                }
//            }
//        } catch (IOException e) {
//            terminal.writeTo("\nConnection to server lost.");
//            recievingData = false;
//        }
//    }

    @Override
    public void processLocalCommand(String input) {
        if (input.equalsIgnoreCase("DISCONNECT") || input.equalsIgnoreCase("QUIT")) {
            disconnect();
        }
    }

    @Override
    public void sendData(String input) {
        if (recievingData) {
            out.println(input);
        } else {
            terminal.writeTo("\nNot connected!");
        }
    }

    @Override
    public void disconnect() {
        if (recievingData) {
            terminal.writeTo("\nDisconnecting...\n");
            recievingData = false;
            out.println("DISCONNECT");
        }
    }
}
